<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=utf-8"/>
    <meta name="description" content="WebWheel是一个超轻量级的java web开发框架，简单就是美是框架的第一宗旨，致力于MVC的最佳化实践以及最彻底的分离页面与逻辑。"/>
    <meta name="keywords" content="WebWheel,Java web framework,MVC,ORM,IOC,DI,javaEE,web开发框架" />
    <title>WebWheel | Java Web Framework</title>
    <link rel="stylesheet" type="text/css" href="site.css"/>
</head>
<body>
<img src="imgs/logo.gif"/>
<img src="imgs/title.png"/>

<div id="navigator">
    <a href="index.html">首页</a>
    <a href="userguide.html">用户手册</a>
    <a href="tutorial.html">实践指南</a>
    <a href="example.html">样例</a>
    <a href="faq.html">常见问题</a>
    <a href="download.html">下载</a>
    <a href="javadoc/index.html">APIdoc</a>
    <a href="lincense.html">版权声明</a>
    <a href="bbs">论坛</a>
</div>
<div id="body">
    <ol>
        <li><a href="#env">环境搭建</a></li>
        <li><a href="#firstpage">第一个页面</a></li>
        <li><a href="#param">http参数</a></li>
        <li><a href="#firstact">第一个动作</a></li>
        <li><a href="#template">模板引擎</a></li>
        <li><a href="#autobind">约定映射规则</a></li>
        <li><a href="#result">结果类与结果类解释器</a></li>
    </ol>
    <hr/>
    <h3 id="env">1.搭建环境</h3>
    <p>
        首先请确定您拥有<a href="http://java.sun.com/javase/downloads/index.jsp">jdk6</a>或更高版本的java开发包，
        并且拥有一个支持servlet 2.4或更高版本的app容器，如<a href="http://tomcat.apache.org/download-60.cgi">tomcat 6</a>，
        然后在<a href="download.html">下载页</a>下载<a href="">webwheel-1.0-rc.jar</a>，随意使用您喜欢的开发工具，推荐<a href="http://www.jetbrains.com/idea/">IntelliJ IDEA</a>:)
    </p>
    <p>
        创建一个空白的web应用的目录，我们取目录名为FirstApp，如下图所示：<br/>
        <img src="imgs/tutorial1.jpg" style="display:block;margin-left:50px"/>
    </p>
    <p>
        web.xml文件内容如下：
        <code>
            <pre>&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee
    http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"&gt;
    &lt;filter&gt;
        &lt;filter-name&gt;WebWheel&lt;/filter-name&gt;
        &lt;filter-class&gt;cn.webwheel.WebWheelFilter&lt;/filter-class&gt;
        &lt;init-param&gt;
            &lt;param-name&gt;main&lt;/param-name&gt;
            &lt;param-value&gt;<span style="color:darkgreen;">firstapp.WebMain</span>&lt;/param-value&gt;
        &lt;/init-param&gt;
    &lt;/filter&gt;
    &lt;filter-mapping&gt;
        &lt;filter-name&gt;WebWheel&lt;/filter-name&gt;
        &lt;url-pattern&gt;/*&lt;/url-pattern&gt;
    &lt;/filter-mapping&gt;
&lt;/web-app&gt;</pre>
        </code>
    </p>
    <p>
        在classes目录下创建app入口类firstapp.WebMain<br/>
        <img src="imgs/tutorial2.jpg" style="display:block;margin-left:50px"/>
    </p>
    <p>
        WebMain.java文件内容如下：
        <code>
            <pre>package firstapp;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class WebMain extends DefaultMain {
	protected void init() {
	}
}</pre>
        </code>
    </p>
    <p>
        如果正常的话，现在就可以编译和部署了，在classes目录下执行编译命令：
        <code><pre>javac -cp ../lib/webwheel-1.0-rc.jar firstapp/*.java</pre></code>
        然后将整个FirstApp目录拷贝到web服务器的应用列表目录，如tomcat下的webapps目录。（以下章节中，我将省略掉编译和部署步骤，希望您能首先学习javaEE的基本常识）
    </p>

    <h3 id="firstpage">2.第一个页面</h3>
    <p>
        下面我们来创建一个动态页面，首先在应用根目录建立网站的首页文件index.html，然后在firstapp.web包下面新建一个类，名字为PageIndex。
        <img src="imgs/tutorial3.jpg" style="display:block;margin-left:50px"/>
    </p>
    <p>
        index.html内容如下：（<strong>注意</strong>文件编码格式为utf-8）
        <code>
            <pre>&lt;!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"&gt;
&lt;html xmlns="http://www.w3.org/1999/xhtml"&gt;
&lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=utf-8"/&gt;
    &lt;title&gt;FirstApp首页&lt;/title&gt;
&lt;/head&gt;
&lt;body&gt;
Hello ${message}!
&lt;/body&gt;
&lt;/html&gt;</pre>
        </code>
    </p>
    <p>
        PageIndex内容如下：
        <code>
            <pre>package firstapp.web;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class PageIndex extends DefaultPage {
	public String message = "WebWheel";
}</pre>
        </code>
    </p>
    <p>
        PageIndex与index.html所对应，二者的对应关系为：java类名去掉Page开头后首字母小写并在末尾加上后缀.html即html文件的文件名。PageIndex类需要继承自DafaultPage类才能构成映射关系，index.html文件需要满足xml规范，否则格式将出错。WebWheel模板引擎使用${}符号作为表达式解释操作符，如这里的${message}将使用PageIndex的公开属性message进行替换和动态渲染到浏览器。
    </p>
    <p>
        最后，我们需要更改一下WebMain类的代码，告诉框架自动配置firstapp.web包下面的类文件。
        <code>
            <pre>package firstapp;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class WebMain extends DefaultMain {
	protected void init() throws Exception {
		<b>autoBind("firstapp.web");</b>
	}
}</pre>
        </code>
        （粗体显示的为更改部分）
    </p>
    <p>
        autoBind方法的参数为一个包路径，调用autoBind方法后，框架将扫描此包下面的所有符合条件的页面、组件、动作三种java类，并根据约定进行配置（后面的章节将会详细叙述）。例如这里的PageIndex类，将被映射到/index.html这个uri并且和index.html页面模板装配到一起来执行http响应。
    </p>
    <h3 id="param">3.http参数</h3>
    <p>
        在动态网站中，http参数的传递几乎是必然会用到的，在WebWheel框架中，http参数通过DI方式进行传递，例如上面的PageIndex类中的message属性，如果我们不希望它是一成不变的，而是通过http参数传递而得的，那么我们可以如此来修改其代码：
        <code>
            <pre>package firstapp.web;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class PageIndex extends DefaultPage {
	public String message = "WebWheel";

	<b>@WebParam("msg")
	public void setMessage(String msg) {
		if(msg != null) message = msg;
	}</b>
}</pre>
        </code>
        使用WebParam注释标识需要注入http参数的地方，可以是公开的属性，也可以是公开的方法或构造方法以及其参数。http参数的类型支持：Map&lt;String, String[]&gt;、String、String[]、boolean、byte、byte[]、short、short[]、int、int[]、long、long[]、float、float[]、double、double[]。WebParam的唯一参数即http参数的名称，如这里的msg即对应下述index.html页面上的链接index.html?msg=Beijing中的msg参数名。
    </p>
    <p>
        为了方便测试，我们将index.html进行修改，如下（仅显示body部分）：
        <code>
            <pre>&lt;body&gt;
Hello ${message}!
<b>&lt;br/&gt;
index.html &lt;a href="index.html"&gt;无参数链接&lt;/a&gt;
&lt;br/&gt;
index.html?msg=Beijing &lt;a href="index.html?msg=Beijing"&gt;有参数链接&lt;/a&gt;</b>
&lt;/body&gt;</pre>
        </code>
    </p>
    <p>
        现在您可以将程序编译部署并看到效果了。
    </p>

    <h3 id="firstact">4.第一个动作</h3>
    <p>
        有很多情况下，客户端的请求并不是一个具体页面，而是提交一个动作，例如注册用户、添加日志等等，这时服务器不但要完成动作执行的任务，也要完成页面跳转的工作，也就是MVC中的C的角色。WebWheel提供了方便的手段用以复用动作或者页面。（WebWheel最佳实践中将会提出，服务器端并不适合做C的角色）
    </p>
    <p>
        我们将在index.html页面上加入一个form表单，将一个message参数传递给动作类，然后动作类做相应处理后跳转到首页。index.html内容增加如下：
        <code>
            <pre>index.html?msg=Beijing &lt;a href="index.html?msg=Beijing"&gt;有参数链接&lt;/a&gt;
<b>&lt;form action="action.do" method="post"&gt;
    信息：&lt;input name="sendmsg.do"/&gt;&lt;input type="submit" value="提交表单"/&gt;
&lt;/form&gt;</b>
&lt;/body&gt;</pre>
        </code>
    </p>
    <p>
        然后在firstapp.web包下面新建一个类，名为ActSendmsg，内容如下：
        <code>
            <pre>package firstapp.web;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class ActSendmsg extends DefaultAction {

	@WebParam("message")
	public String message;

	public Object execute() throws Exception {
		if(message != null) message = message.replace("&lt;", "&amp;lt;");
		PageIndex page = get(PageIndex.class);
		page.setMessage(message);
		return page.execute();
	}
}</pre>
        </code>
        首先，在触发函数execute里，如果参数message不为空，则替换其中的&lt;符号为&amp;lt;，然后使用get方法从DI容器中获得一个页面类实例，设置其message属性，并用其进行渲染页面（调用execute）。
    </p>
    <p>
        现在，请重新编译部署应用，并在index.html的表单输入框中输入包含&lt;符号的文字验证结果，
    </p>

    <h3 id="template">5.模板引擎</h3>
    <p>
        WebWheel最大的特色之一即在于其独到的模板引擎技术，利用三类特殊的标签属性，做到了对html最大化的友好，使页面开发人员和java程序员可以最大程度的进行并行开发。<br/>
        首先，修改index.html内容如下，然后我再来一一解释：
        <code>
            <pre>&lt;/form&gt;
<b>&lt;h4&gt;1.表达式输出&lt;/h4&gt;&lt;br/&gt;
${svalue}
${svalue.hashCode}
${svalue.class.name}
${revert(svalue)}
${revert(svalue).length}
${revert(svalue).toString().toCharArray()[0]}
&lt;div title="${svalue}"&gt;${svalue}&lt;/div&gt;
被silence处理的错误表达式：${abcdefg}
&lt;br/&gt;
&lt;h4&gt;2.标签输出&lt;/h4&gt;&lt;br/&gt;
&lt;div w:tag="tag" w:style="background-color:yellow;${style}" w:content="${content}"&gt;I will disappear&lt;/div&gt;
&lt;br/&gt;
&lt;h4&gt;3.逻辑控制&lt;/h4&gt;&lt;br/&gt;
&lt;div q:tag="tagout"&gt;我是内容，会出现&lt;/div&gt;
&lt;div style="color:red" q:style="false" q:content="false"&gt;我是内容，会消失，我的样式，也会消失&lt;/div&gt;
&lt;div q:="rand&gt;0.5"&gt;我，完全会消失，也许不会&lt;/div&gt;
&lt;h4&gt;4.循环和组件输出&lt;/h4&gt;&lt;br/&gt;
&lt;div w:="svalue"&gt;
    &lt;span&gt;${revert(this)}&lt;/span&gt;
    &lt;span w:content="hashCode"&gt;hahaha&lt;/span&gt;
    &lt;div w:="revert(this)" title="${this}"&gt;
        ${this} ${hashCode}
    &lt;/div&gt;
&lt;/div&gt;
&lt;div w:="array" title="第${_idx+1}个${this}"&gt;
    第${_idx+1}个上下文字符串是"${this}" hashCode：${hashCode}
&lt;/div&gt;
这行是保留的缝隙，注意上下文不是array的元素，而是上一级${this}
&lt;div w:="array" title="第2个hahha"&gt;
    因为array是数组，所以我会消失
&lt;/div&gt;
&lt;h4&gt;5.变量定义&lt;/h4&gt;
&lt;div v:ss="svalue"&gt;
    ${revert(ss)} - ${ss.hashCode}
&lt;/div&gt;
&lt;h4&gt;6.外部组件&lt;/h4&gt;
&lt;div w:="*outer"/&gt;
&lt;/body&gt;</b>
&lt;/body&gt;</pre>
        </code>
    </p>
    <p>
        WebWheel模板引擎拥有自己的表达式语言（以下简称WEL），其语法和java语言表达式基本相同，不同点在于：如果方法名称以get或者is开头则可以省略掉get或is并将其后的字符小写，如果方法的参数个数为0则可省略掉小括号，例如
        <code>
            <pre>java: a.foo()
WEL:   a.foo() 或 a.foo

java: a.getLuck()
WEL:   a.getLuck() 或 a.luck() 或 a.getLuck 或 a.luck

java: a.isFunny()
WEL:   a.isFunny() 或 a.funny() 或 a.isFunny 或 a.funny

java: a.dowith(b.getHead()[0])
WEL:   a.dowith(b.head[0]) 或 ...</pre>
        </code>
        参见上述index.html页面中的第一部分。<br/>
        如果页面上WEL解析失败，则WebWheel模板引擎做忽略处理，视其为普通的文本（非表达式）做处理。
    </p>
    <p>
        WEL可支持的数值运算符和逻辑运算符包括：+ - * / % &lt; &lt;= &gt; &gt;= == != && || ?:，运算符的优先级与java语言表达式相同。支持数组取值操作。
    </p>
    <p>
        WEL可支持的常量包括：字符串，数值常量，true，false，null。
    </p>
    <p>
        WEL不支持类常量，如String.class，不支持字符常量，不支持位操作。
    </p>
    <p>
        WEL的执行始终是在一个树状结构的对象上下文之下进行的，顶级对象即当前的模板组件对象（模板所对应的java类的实例），下级为当前表达式所在位置所处的dom组件对象。当WEL求值时，将从内层组件对象逐级向上查找匹配方法，直至模板组件对象（下面会有详细解释）。
    </p>
    <p>
        WEL可以使用${}符号进行标识，如index.html中的${svalue.hashCode}，将会执行表达式svalue.hashCode，并将其结果输出在页面中的相应位置。
    </p>
    <p>
        WebWheel页面模板利用三类标签属性进行动态内容控制，分别以w: q: v:开头，代表：输出、是否输出、变量定义三种功能。
        <dl>
        <dt>w:</dt>
        <dd>
            以w:打头的属性含义为动态输出属性值的内容，w:后面的名称为输出的当前标签的属性名称，如index.html中的w:style="background-color:yellow;${style}"，将使用"background-color:yellow;"字符串加上对style表达式求值的结果来进行对当前标签style属性的渲染。<br/>
            w:后面有三种内容是特殊的情况：w:tag含义为动态输出标签名称，而不是名为tag的属性，如index.html中的w:tag="tag"，含义为使用对表达式tag求值的结果作为标签名称，替换掉当前div这个名字；w:content含义为动态输出标签内容，同w:tag同理，并非输出名为content的属性，参见index.html中的w:content="${content}"；如果w:后面没有任何内容，则代表是当前dom为一个模板组件，其表达式求值将以w:属性的求值结果作为上下文，稍后详细叙述。<br/>
            值得注意的还有一点，w:和q:属性的值如果全部是WEL，则可省略掉${}标识，例如index.html中的w:tag="tag"与w:tag="${tag}"效果是等同的。
        </dd>
        <dt>q:</dt>
        <dd>
            以q:打头的属性含义为是否输出对应属性，q:后面的名称为是否要输出的当前标签的属性名称，q:的属性值中的WEL的求值结果将决定是否输出，如index.html中的q:style="false"，含义就是不输出当前标签的style属性（依据对常量表达式false的求值结果），q:的属性值中的WEL可以为任何类型，当其求值结果为该类型的默认值时，则为假（不输出），否则为真（输出）。例如对于boolean类型，true为真，false为假，对于int类型，非0为真，0为假，对于对象类型，非null为真，null为假。<br/>
            与w:相同，q:后面也有三种内容是特殊的情况：q:tag代表是否输出标签本身（不包含标签中的内容）；q:content代表是否输出标签内容（不包含标签本身）；q:（后面没有任何文字）代表是否输出整个标签（包括标签本身和标签内容）。
        </dd>
        <dt>v:</dt>
        <dd>
            以v:打头的属性含义为在当前的标签范围内声明并定义一个变量，变量的名称为v:后面的文字内容，变量的值为v:的属性值中的WEL表达式的值。如index.html中第5部分的v:ss="svalue"，代表声明一个变量ss，其值是对svalue这个表达式的求值结果，其作用域为当前div标签以及标签内部。
        </dd>
        <dt>模板组件及循环模板组件</dt>
        <dd>
            当w:（后面没有任何文字）作为一个模板标签属性名称的时候，其含义发生了特殊变化，并不代表输出动态内容，而是代表整个标签都会作为一个动态内容，而此动态内容的上下文就是w:的属性值中的WEL表达式求值结果。<br/>
            在前面对WEL进行说明的时候就已经讲到：每个表达式都会有一个树状的上下文，而这个上下文树就是我们现在讲到的w:所在的标签树，如下：
            <code>
                <pre>${exp0}
&lt;div w:="obj1" attr="${exp1}"&gt;
	${exp1}
	&lt;div w:="obj2" attr="${exp2}"&gt;
		${exp2}${this}
	&lt;/div&gt;
	&lt;div w:="obj3" attr="${exp3}"&gt;
		${exp3}
		&lt;div w:="obj4" attr="${exp4}"&gt;
			${exp4}
		&lt;/div&gt;
	&lt;/div&gt;
&lt;/div&gt;</pre>
            </code>
            此模板中每个表达式exp对应的上下文都是相同编号的obj（exp0的上下文为模板所对应的java类对象），例如exp3对应obj3。每个表达式首先对于当前上下文进行求值，如果求值失败，再使用父级上下文，直至模板java类对象。<br/>
            例如exp4会依次试验obj4、obj3、obj1和模板java类直至表达式解析成功。假设exp4表达式为${substring(4)}，obj1类型为String，obj3类型为Integer，obj4类型为Date，因为只有obj1才有对应于substring的方法，所以这个WEL会在obj1上进行求值，也就是会调用obj1的substring方法。<br/>
            WEL中还有一个特殊的关键字：this，它代表的就是当前的上下文对象，例如在${exp2}之后出现的${this}就是输出obj2对象。<br/>
            值得注意的是，obj4本身也是一个表达式，其求值的过程与${}包含的表达式相同，其当前上下文即obj3。<br/>
            <br/>
            当上下文对象的类型为数组、java.util.Iterator或java.lang.Iterable类型时，则其含义为循环输出当前标签，使用集合元素对象作为标签上下文，如index.html中的w:="array"属性，则会对表达式array求值，因为其返回值类型为String[]，所以将循环渲染当前div标签，并使用String[]中的每一个String作为div标签内表达式的解析上下文。<br/>
            当w:属性为集合类时（上面所说的三种类型），如果相同表达式的w:所在的标签连续排列，则模板引擎会忽略掉后面的标签，而是仅循环一次显示，在前两个相同w:表达式的标签之间的内容会被保留，并在循环中输出，如index.html中的“这行是保留的缝隙，注意上下文不是array的元素，而是上一级${this}”这一部分。<br/>
            对于循环标签，不仅仅存在特殊的关键字：this（含义与非循环标签一样），还有另外一个关键字：_idx，其含义是当前循环的集合索引，从0开始。<br/>
            当需要强制不作为循环组件进行渲染的时候，需要在w:表达式的前面加一个-字符，则框架将忽略此上下文对象的集合类型，而以普通的非循环上下文对象的形式使用。
        </dd>
        <dt>外部组件</dt>
        <dd>
            WebWheel模板引擎中的外部组件机制为模板的重用提供了最大的便利，外部组件相当于jsp中的动态include，当w:属性的值中的WEL以*号为前缀时，则指示当前的dom标签将由外部的模板组件渲染。例如index.html中的w:="*outer"，它使用表达式outer的返回值作为外部组件的上下文对象，根据约定使用outer.html文件作为模板，共同对当前标签进行替换渲染。<br/>
            outer.html内容如下：
            <code>
                <pre>&lt;div&gt;
我是${msg}
&lt;/div&gt;</pre>
            </code>
            它也必须满足WebWheel模板的要求（松散的xml）。<br/>
            <b>注意：</b>外部模板组件使用对应的组件类作为树状上下文对象结果的根，其中的表达式与当前的模板没有关系。如上述的${msg}表达式，它的解释上下文为CompOuter类，与PageIndex类没有任何关系。
        </dd>
        </dl>
    </p>
    <p>
        上述index.html模板与outer.html模板分别对应的组件类是PageIndex与CompOuter，源码如下：<br/>
        PageIndex.java
        <code>
            <pre>package firstapp.web;
import cn.webwheel.*;
import cn.webwheel.utils.*;

public class PageIndex extends DefaultPage {
	public String message = "WebWheel";

	@WebParam("msg")
	public void setMessage(String msg) {
		if(msg != null) message = msg;
	}

	public String svalue = "svalue";

	public StringBuilder revert(String s) {
		if(s==null) return null;
		StringBuilder sb = new StringBuilder();
		for(int i=s.length()-1; i&gt;=0;i--) sb.append(s.charAt(i));
		return sb;
	}

	public String getTag() {
		return "span";
	}

	public String getStyle() {
		return "color:blue";
	}

	public String getContent() {
		return "I am content";
	}

	public boolean tagout() {
		return false;
	}

	public double getRand() {
		return Math.random();
	}

	public String[] getArray() {
		return new String[]{"Chiang", "Kai", "shek"};
	}

	public Object getOuter() {
		return new CompOuter();
	}
}</pre>
        </code>
        CompOuter.java
        <code>
            <pre>package firstapp.web;

public class CompOuter {
	public String msg = "外部组件";
}</pre>
        </code>
    </p>
    <h3 id="autobind">6.约定映射规则</h3>
    <p>
        WebWheel框架使用DefaultMain.autoBind方法执行http请求和页面模板的约定映射（同时可进行更加自由的手工映射）。
    </p>
    <p>
        autoBind方法需要一个字符串类型的参数，代表需要映射的包路径，它将扫描此包下符合若干规则的类并对其进行映射。
    </p>
    <p>
        可映射的类分为三种：页面类，模板组件类和动作类，分别要求以Page、Comp和Act作为类名的前缀。
    </p>
    <p>
        对于动作类，要求此类必须直接或间接实现cn.webwhee.Action接口。autoBind截取扫描包以下的动作类的包路径并加上除去前缀的类名和.do后缀作为http请求的路径，并将其绑定到此动作类之上。例如有一个动作类：
        <code>
            <pre>package com.abc.xyz;
public class ActDosome implements Action {
    ...
}</pre>
        </code>
        当在DefaultMain.init方法中执行autoBind("com.abc")后，即会调用DefaultMain.bindAction("/xyz/dosome.do", ActDosome.class)方法进行绑定。当http请求为/xyz/dosome.do时此动作类将会被触发。
    </p>
    <p>
        对于模板组件类，要求与此类相对于扫描包的同样类路径位置，在web应用下有同名的模板文件。例如有一个模板类：
        <code>
            <pre>package com.abc.xyz;
public class CompTemp {}</pre>
        </code>
        并且在web应用目录的子目录xyz下具有一个文件名为temp.html：
        <code>
            <pre>&lt;div&gt;
    ...
&lt;/div&gt;</pre>
        </code>
        当在DefaultMain.init方法中执行autoBind("com.abc")后，即会调用DefaultMain.bindComponent(CompTemp.class, "/xyz/temp.html")方法进行模板绑定。这时，当页面中引入外部模板，w:表达式的返回值类型为CompTemp或其子类时，外部模板将会正常渲染。
    </p>
    <p>
        对于页面类，必须要同时满足动作类和模板组件类的要求，并以Page为类名前缀。例如有一个页面类：
        <code>
            <pre>package com.abc.xyz;
public class PageIndex extends DefaultPage {
    ...
}</pre>
        </code>
        并且在web应用目录的子目录xyz下具有一个文件名为index.html：
        <code>
            <pre>&lt;div&gt;
    ...
&lt;/div&gt;</pre>
        </code>
        当在DefaultMain.init方法中执行autoBind("com.abc")后，即会调用DefaultMain.bindPage("/xyz/index.html", PageIndex.class)方法进行模板绑定。这时，当/xyz/index.html的http请求到达框架时，此类将被触发，并且通过DefaultPage的默认execute方法返回模板渲染结果。<br/>
        <b>注：</b>DefaultPage.execute方法只有一行：return new TemplateResult(this)。当this对象为模板组件类时才可生效，因为bindPage方法中绑定了此类为模板组件类，所以这里这样使用没有问题。
    </p>
    <h3 id="result">7.结果类与结果类解释器</h3>
    <p>
        Action接口唯一的方法execute的返回值在逻辑上是动作执行的结果，如何解释这些结果是通过结果类解释器完成的。在WebWheel中有一个结果类解释器的注册表，每一个结果类类型被映射到一个结果类解释器实例，当框架得到一个Action返回的结果时，便在此注册表中找到最适合的解释器，并把解释权利交给它。查找解释器的过程为先使用结果对象的类型找对应的解释器，再按照结果对象的接口找，如果仍未找到则取得父级类型按此规则递归查找。
    </p>
    <p>
        注册结果类解释器通过Main.registerResultType方法进行，此方法的签名为：
        <code>
            <pre>public final &lt;T&gt; void registerResultType(Class&lt;T&gt; resultType, ResultInterpreter&lt;? extends T&gt; interpreter)</pre>
        </code>
        第一个参数为结果对象的类型，第二个参数为结果解释器实例。
    </p>
    <p>
        WebWheel内建有两个结果解释器，一个是模板结果TemplateResult的解释器TemplateResultInterpreter，一个是简单结果SimpleResult的解释权SimpleResultInterpreter。
    </p>
    <p>
        模板结果TemplateResult主要有两个参数，一个是模板文件的位置，一个是组件类或组件实例，当使用autoBind或通过bindPage/bindComponent进行绑定之后，则TemplateResult里面的模板文件位置便可忽略。
    </p>
</div>
</body>
</html>